using System;
using System.Web.Routing;
using ManagedUIFlow.Infrastructure.Services.Helpers;
using ManagedUIFlow.Model;

namespace ManagedUIFlow.Infrastructure.Services
{      
    public class BasicSessionFlowViewService : IFlowViewService
    {
        private FlowService _flowService;
        public const string RedirectTicketKey = "PostRedirectGetServiceTicket";
        public const string RedirectUrlKey = "PostRedirectGetServiceUrl";

        public FlowService FlowService
        {
            get
            {
                return _flowService ?? FlowService.Current;
            }
            set { _flowService = value; }
        }
        
        public string Serialize(ManagedFlow flow, RequestContext requestContext)
        {
            if (flow.Redirectable != RedirectBehavior.Auto)
                throw new InvalidOperationException(
                    string.Format("The flow redirectable behaviour should be Auto to use the service type {0}",
                                  GetType()));
            
            requestContext.HttpContext.Session.Add(flow.Key.ToString(), flow);            
            return flow.Key.ToString();
        }

        public ManagedFlow Deserialize(string key, RequestContext requestContext)
        {
            if (IsRedirectBack(requestContext))
                return requestContext.HttpContext.Session[RedirectTicketKey] as ManagedFlow;

            var flow = requestContext.HttpContext.Session[key] as ManagedFlow;
            if (flow != null)
            {
                var newNavigation = FlowService.GetNavigationFor(flow.Name, flow.CurrentNavigation,
                                                                 requestContext.GetState());
                flow.SetNavigation(newNavigation);
                return flow;
            }

            throw new FlowException(
                     "Either you have used browser refresh button or unable to restore the flow.");
        }

        public void PostRedirectGet(string key, ManagedFlow flow, RequestContext context)
        {
            if (IsRedirectBack(context))
            {
                context.HttpContext.Session.Remove(RedirectTicketKey);
                return;
            }
            context.HttpContext.Session.Add(RedirectTicketKey, flow);
            if (context.HttpContext.Session[RedirectUrlKey] == null)
            {
                var redirectUrl = !string.IsNullOrEmpty(flow.RedirectUrl)
                                      ? flow.RedirectUrl
                                      : flow.Name;
                context.RouteData.Values["controller"] = flow.Key.ToString();
                var url = UrlHelper.GenerateUrl(null, redirectUrl, null,
                                                new RouteValueDictionary(),
                                                RouteTable.Routes, context, false
                    /* includeImplicitMvcValues */);
                context.HttpContext.Session.Add(RedirectUrlKey, url);
            }
            context.HttpContext.Response.Redirect(context.HttpContext.Session[RedirectUrlKey].ToString());     
        }

        public void Remove(ManagedFlow flow, RequestContext requestContext)
        {
            requestContext.HttpContext.Session.Remove(flow.Key.ToString());
        }
      
        private static bool IsRedirectBack(RequestContext requestContext)
        {
            return requestContext.HttpContext.Session[RedirectTicketKey] != null;
        }
    }
}